﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Acme.Sales.EFDAL;
using Acme.Sales.EFDAL.Entity;

namespace TestApplication
{

	public class UnitTest1
	{
		public void RunTests()
		{
			try
			{
				//This set of methods adds objects in the proper order to populate a database.
				//See the Schema.png for a database schema
				AddCustomers();
				AddEmployees();
				AddRegions();
				AddTerritories();
				AddEmployeeTerritories();
				SelectObjects();
				UpdateObjects();
				DeleteObjects();
			}
			catch (Exception ex)
			{
				throw;
			}
		}

		/// <summary>
		/// Add a number of Customers (derived from SYSTEM_USER)
		/// </summary>
		private void AddCustomers()
		{
			ContextStartup am = new ContextStartup("user14");
			using (SalesEntities context = new SalesEntities(am))
			{
				//Add 10 customers
				for (int ii = 0; ii < 10; ii++)
				{
					//Notice that all fields from Customer are here and all base fields from SystemUser are present as well
					//There is no need to define a PK since the base SystemUser entity defines a PK as an integer identity
					Customer newItem = new Customer();
					newItem.Code = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.Code));
					newItem.Address = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.Address));
					newItem.City = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.City));
					newItem.CompanyName = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.CompanyName));
					newItem.Country = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.Country));
					newItem.Fax = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.Fax));
					newItem.FirstName = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.FirstName));
					newItem.LastName = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.LastName));
					newItem.Phone = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.Phone));
					newItem.PostalCode = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.PostalCode));
					newItem.Region = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.Region));
					newItem.Title = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.Title));
					context.AddItem(newItem);
				}
				context.SaveChanges();
			}
		}

		/// <summary>
		/// Add a number of Employees (derived from SYSTEM_USER)
		/// </summary>
		private void AddEmployees()
		{
			using (SalesEntities context = new SalesEntities())
			{
				//Add 10 employees
				for (int ii = 0; ii < 10; ii++)
				{
					//Notice that all fields from Employee are here and all base fields from SystemUser are present as well
					Employee newItem = new Employee();
					newItem.BirthDate = new DateTime(2010, 1, 1);
					newItem.Address = this.RandomString(Employee.GetMaxLength(Employee.FieldNameConstants.Address));
					newItem.City = this.RandomString(Employee.GetMaxLength(Employee.FieldNameConstants.City));

					//Assign an employee type via Enumeration to this object
					//Employee types are defined as a typep table and have a generated enum with them
					//The database actually holds an integer foreign key and a relationship to that type table
					if ((rnd.Next(0, 2) % 2) == 0)
						newItem.EmployeeType = Acme.Sales.EFDAL.EmployeeTypeConstants.BigFish;
					else
						newItem.EmployeeType = Acme.Sales.EFDAL.EmployeeTypeConstants.Normal;

					newItem.HireDate = new DateTime(2010, 2, 1);
					newItem.Notes = this.RandomString(Employee.GetMaxLength(Employee.FieldNameConstants.Notes));
					newItem.Country = this.RandomString(Employee.GetMaxLength(Employee.FieldNameConstants.Country));
					newItem.Fax = this.RandomString(Employee.GetMaxLength(Employee.FieldNameConstants.Fax));
					newItem.FirstName = this.RandomString(Employee.GetMaxLength(Employee.FieldNameConstants.FirstName));
					newItem.LastName = this.RandomString(Employee.GetMaxLength(Employee.FieldNameConstants.LastName));
					newItem.Phone = this.RandomString(Employee.GetMaxLength(Employee.FieldNameConstants.Phone));
					newItem.PostalCode = this.RandomString(Employee.GetMaxLength(Employee.FieldNameConstants.PostalCode));
					newItem.Region = this.RandomString(Employee.GetMaxLength(Employee.FieldNameConstants.Region));
					newItem.Title = this.RandomString(Employee.GetMaxLength(Employee.FieldNameConstants.Title));
					context.AddItem(newItem);
				}
				context.SaveChanges();
			}
		}

		/// <summary>
		/// Add a number of regions
		/// </summary>
		private void AddRegions()
		{
			using (SalesEntities context = new SalesEntities())
			{
				//Add 5 regions
				for (int ii = 0; ii < 5; ii++)
				{
					Region newItem = new Region();
					newItem.Name = RandomString(Region.GetMaxLength(Region.FieldNameConstants.Name));
					context.AddItem(newItem);
				}
				context.SaveChanges();
			}
		}

		/// <summary>
		/// Add a number of Territories
		/// </summary>
		private void AddTerritories()
		{
			using (SalesEntities context = new SalesEntities())
			{
				//Get all regions from the database
				var regionList = (from x in context.Region
													select x).ToList();

				//Add 50 territories (each is associated with an existing region)
				for (int ii = 0; ii < 10; ii++)
				{
					//Create a new territory and define the primary key
					//The PK is a string not an identity so we must specify it
					//You can only set the PK in the constructor. It is read-only.
					Territory newItem = new Territory(RandomString(Territory.GetMaxLength(Territory.FieldNameConstants.TerritoryId)));
					newItem.Name = RandomString(Territory.GetMaxLength(Territory.FieldNameConstants.Name));
					newItem.Region = regionList[rnd.Next(0, regionList.Count)]; //Get a region, it does not matter which for the sample
					context.AddItem(newItem);
				}
				context.SaveChanges();
			}

		}

		/// <summary>
		/// Associate existing Territories with existing Employees
		/// </summary>
		private void AddEmployeeTerritories()
		{
			using (SalesEntities context = new SalesEntities())
			{
				//Get the list of Employees from the database
				var employeeList = (from x in context.Employee
														select x).ToList();

				//Get the list of Territories from the database
				var territoryList = (from x in context.Territory
														 select x).ToList();

				///Loop through the Employee list and associate it with an arbitrary territory
				foreach (Employee employee in employeeList)
				{
					Territory territory = territoryList[rnd.Next(0, territoryList.Count)];
					if (!employee.TerritoryList.Contains(territory))
						employee.TerritoryList.Add(territory);
				}

				//We could just as easily have run this code to do the same thing in the other direction
				//foreach (Territory territory in territoryList)
				//{
				//  territory.EmployeeList.Add(employeeList[rnd.Next(0, employeeList.Count)]);
				//}

				int count = context.SaveChanges();
			}
		}

		private void SelectObjects()
		{
			using (SalesEntities context = new SalesEntities())
			{
				//Entity Framework does not directly support quering descendant objects
				//You must use the "OfType<>" operator in EF on base objects.
				var customers = from x in context.Customer
												select x;

				foreach (var c in customers)
				{
					System.Diagnostics.Debug.WriteLine(c.UserId);
				}

				var employees = from x in context.Employee
												select x;

				foreach (var e in employees)
				{
					System.Diagnostics.Debug.WriteLine(e.UserId);
				}

				var regions = from x in context.Region
											select x;

				foreach (var r in regions)
				{
					System.Diagnostics.Debug.WriteLine(r.RegionId);
				}

			}
		}

		private void UpdateObjects()
		{
			using (SalesEntities context = new SalesEntities())
			{
				//Entity Framework does not directly support quering descendant objects
				//You must use the "OfType<>" operator in EF on base objects.
				var customers = from x in context.Customer
												select x;

				foreach (var c in customers)
				{
					c.Code = this.RandomString(Customer.GetMaxLength(Customer.FieldNameConstants.Code));
				}

				int count = context.SaveChanges();
				System.Diagnostics.Debug.WriteLine("Save Count: " + count);
			}

		}

		private void DeleteObjects()
		{
			using (SalesEntities context = new SalesEntities())
			{
				//Entity Framework does not directly support quering descendant objects
				//You must use the "OfType<>" operator in EF on base objects.
				IEnumerable<Customer> customers = from x in context.Customer
												select x;

				//Delete all objects
				foreach (var c in customers)
				{
					context.DeleteObject(c);
				}

				int count = context.SaveChanges();
				System.Diagnostics.Debug.WriteLine("Delete Count: " + count);

				//Reselect
				customers = from x in context.Customer
										select x;

				count = context.SaveChanges();
				System.Diagnostics.Debug.WriteLine("New Item Count: " + count);

			}

		}

		#region Helpers

		private Random rnd = new Random();

		/// <summary>
		/// Generates a random string of characters
		/// </summary>
		/// <param name="length">The length of the string to generate</param>
		private string RandomString(int length)
		{
			string retval = "";
			if (length < 1) length = 1;
			if (length > 1000) length = 1000;
			for (int ii = 0; ii < length; ii++)
			{
				retval += (char)(97 + rnd.Next(0, 26));
			}
			return retval;
		}

		#endregion

	}
}